La idea en esta presentación es mostrar paso a paso la construcción de un gráfico.
Partiremos del objetivo deseado, en este caso un tipo de gráfico que ya existe, pero podría ser algún otro ejemplo o un bosquejo de lo imaginado garabateado en un papel.
El segundo paso es determinar cuales son las variables necesarias para construir ese gráfico y donde se mapean.
El tercer paso es trabajar con los datos y transformarlos para que estén preparados para graficar.
El cuarto es el gráfico en si mismo con todas las personalizaciones de sus partes.
Gráfico objetivo
Queremos construir un gráfico similar a este
Variables participantes
El análisis del modelo indica que hay dos capas geométricas simultáneas: una de barras y otra de líneas.
También hay dos ejes y (a izquierda Números de casos y a derecha Tasas por 100.000) y un eje x (Años)
Las variables participantes son tres:
el número de casos que mapea en y1,
las tasas que mapean en y2 y
los años de la tendencia que se ubican en x.
Lectura y adecuación de los datos
Importamos datos de la tendencia de TB de la provincia de Santa Fe entre los años 1980 y 2008
library(tidyverse)library(readxl)tendencia1 <-read_excel("Tendencia tb 1980 2008 por provincia.xls", sheet ="SFE", range ="A6:A34", col_names = F) |>rename("Año"= ...1)tendencia2 <-read_excel("Tendencia tb 1980 2008 por provincia.xls", sheet ="SFE", range ="D6:E34", col_names = F) |>rename("Casos"= ...1,"Tasa"= ...2)tendencia <- tendencia1 |>bind_cols(tendencia2)
Lectura y adecuación de los datos
El dataframe necesario para este gráfico nos quedaría así:
Iniciamos con el gráfico de barras. Mapeamos x e y, indicamos color de relleno e identidad porque las barras se van a construir con el conteo previo (datos agregados)
tendencia |>ggplot(aes(x = Año, y = Casos)) +geom_bar(stat ="identity", fill ="royalblue")
Primer gráfico
Capa de texto
Agregamos capa de texto con los valores de los casos.
tendencia |>ggplot(aes(x = Año, y = Casos, label = Casos)) +geom_bar(stat ="identity", fill ="royalblue") +geom_text()
Capa de texto
Capa de texto
Adecuamos los valores en las barras.
tendencia |>ggplot(aes(x = Año, y = Casos, label = Casos)) +geom_bar(stat ="identity", fill ="royalblue") +geom_text(hjust =1.2, vjust =0.5, angle =90, color ="white")
Capa de texto
Eje x
Configuramos eje x
tendencia |>ggplot(aes(x = Año, y = Casos, label = Casos)) +geom_bar(stat ="identity", fill ="royalblue") +geom_text(hjust =1.2, vjust =0.5, angle =90, color ="white") +scale_x_continuous(name ="Años", breaks =seq(1980, 2008, 1))
Eje x
Eje x
Personalizamos mejor el eje x (ángulo de las etiquetas, etc)
Incoporamos el segundo gráfico o segunda capa geométrica. Utilizamos una constante para llevar los valores al mismo orden de los valores de las barras.
tendencia |>ggplot(aes(x = Año, y = Casos, label = Casos)) +geom_bar(stat ="identity", fill ="royalblue") +geom_line(aes(y = Tasa*35), color ="red", linewidth =1.5) +geom_text(hjust =1.2, vjust =0.5, angle =90, color ="white") +scale_x_continuous(name ="Años", breaks =seq(1980, 2008, 1)) +scale_y_continuous(name ="Número de casos", breaks =seq(0, 1000, 200),sec.axis =sec_axis(~./35, name ="Tasa")) +theme(axis.text.x =element_text(angle =45, hjust =1, size =11),axis.text.y =element_text(size =11))
Segundo gráfico
Etiquetas del segundo gráfico
Agregamos etiquetas asociadas a la capa geométrica line
tendencia |>ggplot(aes(x = Año, y = Casos, label = Casos)) +geom_bar(stat ="identity", fill ="royalblue") +geom_line(aes(y = Tasa*35), color ="red", linewidth =1.5) +geom_text(hjust =1.2, vjust =0.5, angle =90, color ="white") +geom_text(aes(label =round(Tasa,1), y = Tasa*35), angle =45, hjust =-0.2, vjust =-0.5) +scale_x_continuous(name ="Años",breaks =seq(1980, 2008, 1)) +scale_y_continuous(name ="Número de casos", breaks =seq(0, 1400, 200),limits =c(0,1400),sec.axis =sec_axis(~./35, name ="Tasas por 100.000", breaks =seq(0, 60, 10))) +theme(axis.text.x =element_text(angle =45, hjust =1, size =11),axis.text.y =element_text(size =11))
Etiquetas del segundo gráfico
Leyendas
Al igual que el modelo del gráfico, sumamos dentro del mismo las leyendas
tendencia |>ggplot(aes(x = Año, y = Casos, label = Casos, fill ="Número de casos")) +geom_bar(stat ="identity") +geom_line(aes(y = Tasa*35, color ="Tasas por 100.000"), linewidth =1.5) +geom_text(hjust =1.2, vjust =0.5, angle =90, color ="white") +geom_text(aes(label =round(Tasa,1), y = Tasa*35), angle =45, hjust =-0.2, vjust =-0.5) +scale_x_continuous(name ="Años",breaks =seq(1980, 2008, 1)) +scale_y_continuous(name ="Número de casos", breaks =seq(0, 1400, 200),limits =c(0,1400),sec.axis =sec_axis(~./35, name ="Tasas por 100.000", breaks =seq(0, 60, 10))) +scale_fill_manual(values ="royalblue") +scale_color_manual(values ="red") +theme(axis.text.x =element_text(angle =45, hjust =1, size =11),axis.text.y =element_text(size =11),legend.position ="inside",legend.position.inside =c(0.8, 0.8),legend.background =element_rect(fill ="transparent"),legend.text.position ="right",legend.title=element_blank()) +guides(color =guide_legend(order =0),fill =guide_legend(order =1))
Leyendas
Título y demás
Por último, definimos estructura de titulo, subtitulo y pie de gráfico (habría que reemplazarlos por la definición de cada uno).
tendencia |>ggplot(aes(x = Año, y = Casos, label = Casos, fill ="Número de casos")) +geom_bar(stat ="identity") +geom_line(aes(y = Tasa*35, color ="Tasas por 100.000"), linewidth =1.5) +geom_text(hjust =1.2, vjust =0.5, angle =90, color ="white") +geom_text(aes(label =round(Tasa,1), y = Tasa*35), angle =45, hjust =-0.2, vjust =-0.5) +scale_x_continuous(name ="Años",breaks =seq(1980, 2008, 1)) +scale_y_continuous(name ="Número de casos", breaks =seq(0, 1400, 200),limits =c(0,1400),sec.axis =sec_axis(~./35, name ="Tasas por 100.000", breaks =seq(0, 60, 10))) +scale_fill_manual(values ="royalblue") +scale_color_manual(values ="red") +labs(title ="Titulo", subtitle ="subtitulo", caption ="pie de grafico" ) +theme(axis.text.x =element_text(angle =45, hjust =1, size =11),axis.text.y =element_text(size =11),legend.position ="inside",legend.position.inside =c(0.8, 0.8),legend.background =element_rect(fill ="transparent"),legend.text.position ="right",legend.title=element_blank()) +guides(color =guide_legend(order =0),fill =guide_legend(order =1))
Título y demás
Gráficos que no hacen lo que quiero
Muchas veces nos encontramos con la situación de crear un gráfico que se ve bien en el panel Plot de RStudio y cuando lo exportamos o incluímos dentro de un documento de Quarto el tamaño de sus partes (elementos geométricos, textos, leyendas, etc) se achican o agrandan de tal forma que el producto final es feo y/o desproporcionado.
La respuesta a estos problemas tienen que ver con dos conceptos que debemos entender y poder controlar: el tamaño y la resolución.
Pantalla
Repasemos algunos conceptos de la imagen en pantalla:
La pantalla es una matriz de pixeles. Todas las imagenes que vemos en ella estan compuesta por ellos.
La que estoy utilizando ahora, para hacer esta presentación, tiene una dimensión de 24 pulgadas con un ratio de aspecto 16/10 (20 x 12,5 pulgadas)
La resolución es de 1920 x 1200, es decir tiene 1920 píxeles de ancho y 1200 píxeles de alto.
El número de píxeles por pulgada es de 96 (ppi).
Pantalla
Hagamos algunos calculos para ver si todo está en orden:
ancho: 1920 (px) / 96 (px/in) = 20 pulgadas
alto: 1200 (px) / 96 (px/in) = 12,5 pulgadas
relación: 1920 / 1200 = 20 / 12,5 = 16/10
Archivos de imagen
Las imágenes que se crean con ggplot2, por ejemplo, están constituidas por pixeles.
En estas imágenes también se relacionan las dimensiones y las resoluciones.
Para pasar de la dimensión en pulgadas a una cantidad de puntos, por ejemplo al exportar con ggsave() se utiliza la cantidad de puntos por pulgadas (dpi).
Si creamos un gráfico de 12 x 10 pulgadas a 300 dpi, el archivo será una matriz de (12 * 300) x (10 * 300) = 3600 x 3000 puntos.
Cuando abrimos el archivo en nuestra computadora, cada punto representa un pixel, lo que da una imagen de 3600 x 3000 px de resolución.
Archivos de imagen
Imaginemos que tenemos una imagen de 500x500px. Así se vería cada una, con un zoom del 100%, en un monitor de 1080p (1920x1080px) y en otro 4K (3840×2160), ambos del mismo tamaño.
Experimento práctico
Hagamos un pequeño experimento con un gráfico sencillo basado en los pinguinos.
library(tidyverse)library(datos)pinguinos |>ggplot(aes(largo_pico_mm, alto_pico_mm, color = especie)) +geom_point()
Ahora si en lugar de guardar el gráfico solo lo visualizaramos en el monitor:
ancho: 10 pulgadas * 96 dpi = 960 px
alto: 5 pulgadas * 96 dpi = 480 px
Experimento práctico
La relación entre el tamaño de la pantalla y el tamaño físico depende del dpi (puntos por pulgada) del dispositivo gráfico, que es 96 por defecto para la pantalla.
Luego, si guardamos el gráfico con un dpi mayor o menor, el archivo se guarda como una matriz de puntos usando el nuevo dpi y el tamaño en pulgadas.
Entonces, cuando se abre en la computadora, la dimensión del tamaño en píxeles es diferente.
Si visualizamos un gráfico con muchos más pixeles que otro en el mismo espacio (nuestra pantalla) los elementos que lo componen se van a ver siempre más pequeños.
¿Por qué es importante esta diferencia?
Importa porque algunos elementos del gráfico se ajustan al espacio disponible, y algunos son fijos y medidos en su dimensión real (cm, mm o pulgadas) como las fuentes de los textos, creando una distorsión al cambiar la dimensión del gráfico o su resolución.
Tamaño predeterminado en Quarto
Formato
Por defecto
Por defecto
7 x 5
Diapositivas HTML
9,5 x 6,5
Diapositivas HTML (reveal.js)
9 x 5
PDF
5,5 x 3,5
Diapositivas PDF (Beamer)
10x7
PowerPoint
7,5 x 5,5
MS Word, ODT, RTF
5x4
EPUB
5x4
* Medidas en pulgadas
Grafico con tamaño predeterminado (9 x 5”)
Grafico con tamaño al 50% (4.5 x 2.5”)
Grafico con tamaño 12 x 6.67”
Archivos exportados
Comparemos dos archivos exportados desde ggplot2:
font_prueba1_5x5_300.png
font_prueba1_10x10_300.png
Problemas con fuentes
Observamos que el tamaño del punto y la fuente parecen más pequeños en el gráfico de la derecha.
De hecho no son más pequeños, siguen teniendo el mismo tamaño en pulgadas, y como guardamos con la misma resolución (dpi = 300), tienen el mismo número de puntos (tamaño en pulgadas * 300).
La fuente del gráfico aparece más pequeña porque el segundo gráfico es más grande (3000x3000 frente a 1500x1500) y se reduce su aspecto para que el gráfico entre el espacio de la pantalla.
Diferencia en tamaño de fuentes
Además tenemos otro problema. De forma predeterminada, el tamaño de las fuentes de la configuración de theme() está definido en pts. (15 significa 15 puntos - pts-).
En cambio, en la capa geom_text(), el tamaño se define en mm, por lo que 15 es 15 mm.
¿Cuál es la relación entre pts y mm o in?
1 punto = 1/72 pulgadas
1 punto = 0,35 mm
Diferencia en tamaño de fuentes
Entonces si queremos que el texto tenga el mismo tamaño que el título, el tamaño en mm será 15 pt * 0,35 pt/mm = 5,25 mm
En ggplot, hay una constante definida para realizar la conversión, .pt = 2,845276. (1/.pt = 0,35). Podemos escribir .pt en la consola y mostrará su valor:
.pt
[1] 2.845276
1/.pt
[1] 0.3514598
Entonces para hacer la conversión:
de pt a mm : mm = pt / .pt -> 15 / 2,845276 = 5,27 mm
de mm a pt : pt = mm * .pt -> 5,27 * 2,845276 = 15 pts
Diferencia en tamaño de fuentes
pinguinos |>ggplot(aes(x = largo_pico_mm, y = alto_pico_mm, color = especie)) +geom_point() +geom_text(x =45, y =20, label ="Ejemplo font 15", size =15, inherit.aes =FALSE) +labs(title ="Relación entre largo y altura de picos por especies") +theme(plot.title =element_text(size =15))
Diferencia en tamaño de fuentes
pinguinos |>ggplot(aes(x = largo_pico_mm, y = alto_pico_mm, color = especie)) +geom_point()+geom_text(x =45, y =20, label ="Ejemplo font 15", size =15/.pt, inherit.aes =FALSE) +labs(title ="Relación entre largo y altura de picos por especies") +theme(plot.title =element_text(size =15))